﻿using PreGUI.Attributes;
using PreGUI.Widgets;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

#region Property Settings Objects
[System.Serializable]
public class TitleBarSettings
{
    public Color BarColor;
    public Font Font;
    public FontStyle FontStyle;
    public Color FontColor;
    public int FontSize;
}

[System.Serializable]
public class CaptionLabelSettings
{
    public Font Font;
    public FontStyle FontStyle;
    public Color FontColor;
    public int FontSize;
}

[System.Serializable]
public class TextEditorSettings
{
    public Font Font;
    public FontStyle FontStyle;
    public Color FontColor;
    public int FontSize;
    public Color BackgroundColor;
    public float Height;
}

[System.Serializable]
public class ButtonSettings
{
    public Font Font;
    public FontStyle FontStyle;
    public Color FontColor;
    public int FontSize;
    public Color BackgroundColor;
    public Color HighlightColor;
    public Color PressedColor;
    public Color DisabledColor;
    public float MinimumHeight;
    public float MinimumWidth;
}
#endregion

public class PreGui : MonoBehaviour
{
    /// <summary>
    /// Camera used to render the GUI
    /// </summary>
    private Camera _uiCamera;

    /// <summary>
    /// Local transform cache to prevent GetComponent<> to be called repeatedly.
    /// </summary>
    private Transform _transform = null;

    /// <summary>
    /// The UI canvas for the elements.
    /// </summary>
    private Canvas _canvas = null;

    /// <summary>
    /// When set to true, causes the system to ignore UI in the main camera.
    /// </summary>
    public bool IgnoreUiOnMainCamera = true;

    /// <summary>
    /// Determines if the gui is ran in debug mode.
    /// </summary>
    public bool DebugMode = true;

    public CursorMode CursorMode;
    public PGCursor CursorTheme;
    public Sprite ControlSprite;
    public Color BackgroundColor;
    public Color PanelColor;
    public TitleBarSettings TitleBarSettings = new TitleBarSettings();
    public CaptionLabelSettings CaptionLabelSettings = new CaptionLabelSettings();
    public CaptionLabelSettings LabelSettings = new CaptionLabelSettings();
    public TextEditorSettings TextEditorSettings = new TextEditorSettings();
    public ButtonSettings ButtonSettings = new ButtonSettings();

    public Dictionary<string, System.Action<object>> FunctionHandlers = new Dictionary<string, System.Action<object>>();
    public Dictionary<string, object> ViewModels = new Dictionary<string, object>();

    void Awake()
    {
        // Cache the transform object so we don't have to keep calling it
        _transform = GetComponent<Transform>();

        // Create the UI canvas object
        var canvasGameObject = new GameObject("Canvas");

        if (!DebugMode)
        {
            canvasGameObject.hideFlags = HideFlags.HideAndDontSave;
        }

        canvasGameObject.transform.SetParent(_transform, false);
        _canvas = canvasGameObject.AddComponent<Canvas>();

        canvasGameObject.AddComponent<CanvasScaler>();
        canvasGameObject.AddComponent<GraphicRaycaster>();

        // And set it up
        _canvas.renderMode = RenderMode.ScreenSpaceOverlay;
        _canvas.pixelPerfect = true;
        _canvas.worldCamera = _uiCamera;

        // Make it a child of this object
        _canvas.transform.SetParent(_transform, false);

        // Set the layer of the GUI system to UI only
        gameObject.layer = LayerMask.NameToLayer("UI");

        // Add the camera to the game object
        _uiCamera = gameObject.AddComponent<Camera>();

        // Configure the camera properties to work with the UI system.
        _uiCamera.clearFlags = CameraClearFlags.Depth;
        _uiCamera.orthographic = true;

        // And set up the culling mask
        SetupCullingMask();

        if (CursorTheme != null)
        {
            Cursor.SetCursor(CursorTheme.Arrow.Image, CursorTheme.Arrow.Offset, CursorMode);
        }
    }

    void Update()
    {
    }

    void SetupCullingMask()
    {
        // Set up the UI camera to only show the UI layer
        _uiCamera.cullingMask = (1 << LayerMask.NameToLayer("UI"));

        // Remove the UI layer from the main camera, if set up to do so
        if (IgnoreUiOnMainCamera)
        {
            Camera.main.cullingMask &= ~(1 << LayerMask.NameToLayer("UI"));
        }
    }

    public PGWindow CreateWindow(PGWindow window)
    {
        var result = new GameObject("PGWindow");
        result.AddComponent<RectTransform>();

        window.Gui = this;
        window.InitializeWindow(result);
        result.transform.SetParent(_canvas.gameObject.transform, false);

        return window;

    }

    public void BindEvent(string functionName, System.Action<object> callback)
    {
        FunctionHandlers[functionName] = callback;
    }

    public void BindViewModel(string windowName, object viewModel)
    {
        ViewModels[windowName] = viewModel;

        // Generate the window if a tag exists for it.
        var windowResourceAttr = (WindowResourceAttribute)System.Attribute.GetCustomAttribute(viewModel.GetType(), typeof(WindowResourceAttribute));
        if (windowResourceAttr == null)
            return;

        CreateWindow(PGWindow.FromResource(windowResourceAttr.WindowResourceName));
    }

}
